package creative.fire.interview.oracle;

/**
 * @author feuyeux@gmail.com 2011-10-13
 */
public class Singleton {
	private Singleton() {
	}

	private static final Singleton singleton = new Singleton();

	public static Singleton getInstance() {
		return singleton;
	}
}

class Singleton2 {
	private Singleton2() {
	}

	private static Singleton2 singleton;

	public static synchronized Singleton2 getInstance() {
		if (singleton == null)
			singleton = new Singleton2();
		return singleton;
	}
}

class Singleton3 {
	private Singleton3() {
	}

	private static Singleton3 singleton;

	/*
	 * 在同步锁代码块内部，再判断一次对象是否为null，为null才创建对象。
	 * 这种写法已经接近完美：
	 * a:线程1执行到1，已经进入synchronized的时候，线程挂起，线程1占有Singleton.class资源锁；
	 * b:线程2执行到1，当它准备synchronized块时，因为Singleton.class被占用，线程2阻塞； 
	 * c:线程1被唤醒，判断出对象为null，执行完创建一个对象 
	 * d:线程2被唤醒，判断出对象不为null，不执行创建语句 如此分析，发现似乎没问题。
	 * 
	 * 但是实际上并不能保证它在单处理器或多处理器上正确运行； 问题就出现在singleton = new Singleton()这一行代码。
	 * 它可以简单的分成如下三个步骤：
	 *  mem= singleton();//1 
	 *  instance = mem;//2 
	 *  ctorSingleton(instance);//3
	 * 这行代码先在内存开辟空间，赋给singleton的引用，然后执行new 初始化数据，但是注意初始化是要消耗时间。
	 * 如果此时线程3在执行步骤1的时候，发现singleton 为非null，就直接返回，那么线程3返回的其实是一个没构造完成的对象。 
	 * 我们期望1,2,3 按照反序执行，但是实际jvm内存模型，并没有明确的有序指定。 这归咎于java的平台的内存模型允许“无序写入”。
	 */
	public static Singleton3 getInstance() {
		if (singleton == null)// 1
			synchronized (Singleton.class) {// 2
				if (singleton == null)// 3
					singleton = new Singleton3();// 4
			}
		return singleton;
	}
}
